"""
音频样本分析器，用于分析样本音频文件的特征
"""
import os
import numpy as np
from scipy.io import wavfile
import matplotlib.pyplot as plt
from app.utils.logger import Logger

class SampleAnalyzer:
    """
    音频样本分析器
    """
    
    def __init__(self):
        """
        初始化音频样本分析器
        """
        self.logger = Logger.get_logger("sample_analyzer")
    
    @staticmethod
    def analyze_silence(file_path, output_folder=None):
        """
        分析音频文件的静音部分
        
        @param file_path: 音频文件路径
        @param output_folder: 分析结果输出文件夹，如果为None则不生成图表
        @return: 包含分析结果的字典
        """
        logger = Logger.get_logger("sample_analyzer")
        
        try:
            # 读取音频文件
            sample_rate, audio_data = wavfile.read(file_path)
            
            # 如果是立体声，转换为单声道以简化处理
            if len(audio_data.shape) > 1:
                audio_data = audio_data.mean(axis=1)
            
            # 将音频数据类型转换为浮点型
            if audio_data.dtype != np.float32 and audio_data.dtype != np.float64:
                audio_data = audio_data.astype(np.float32)
                # 按照数据类型归一化数据
                if audio_data.dtype == np.int16:
                    audio_data = audio_data / 32768.0
                elif audio_data.dtype == np.int32:
                    audio_data = audio_data / 2147483648.0
                else:
                    audio_data = audio_data / np.max(np.abs(audio_data))
            
            # 计算音频包络线
            envelope = np.abs(audio_data)
            
            # 使用移动平均平滑包络
            window_size = int(sample_rate * 0.01)  # 10ms窗口
            if window_size > 1:
                smooth_envelope = np.convolve(envelope, np.ones(window_size)/window_size, mode='same')
            else:
                smooth_envelope = envelope
            
            # 计算静音统计信息
            # 静音部分定义为前10%和后10%
            front_size = int(len(audio_data) * 0.1)
            back_size = int(len(audio_data) * 0.1)
            
            front_envelope = smooth_envelope[:front_size]
            back_envelope = smooth_envelope[-back_size:]
            
            # 计算统计数据
            front_mean = np.mean(front_envelope)
            front_max = np.max(front_envelope)
            front_std = np.std(front_envelope)
            
            back_mean = np.mean(back_envelope)
            back_max = np.max(back_envelope)
            back_std = np.std(back_envelope)
            
            # 设置建议的阈值 (平均值 + 2个标准差)
            front_threshold = front_mean + 2 * front_std
            back_threshold = back_mean + 2 * back_std
            
            # 取两者的最大值作为建议阈值
            suggested_threshold = max(front_threshold, back_threshold)
            
            # 查找使用不同阈值的切割点
            thresholds = [0.01, 0.02, 0.03, 0.05, 0.1, suggested_threshold]
            cut_points = {}
            
            for threshold in thresholds:
                # 查找开始和结束的非静音点
                non_silence = smooth_envelope > threshold
                
                if not np.any(non_silence):
                    cut_points[threshold] = (0, len(audio_data)-1)
                    continue
                
                # 找到第一个非静音点
                start_idx = np.where(non_silence)[0][0]
                
                # 找到最后一个非静音点
                end_idx = np.where(non_silence)[0][-1]
                
                cut_points[threshold] = (start_idx, end_idx)
            
            # 如果指定输出文件夹，则生成分析图表
            if output_folder:
                try:
                    os.makedirs(output_folder, exist_ok=True)
                    
                    # 提取文件名作为图表标题
                    file_name = os.path.basename(file_path)
                    base_name, _ = os.path.splitext(file_name)
                    output_file = os.path.join(output_folder, f"{base_name}_silence_analysis.png")
                    
                    # 生成时域波形图
                    plt.figure(figsize=(15, 10))
                    
                    # 绘制原始音频波形
                    plt.subplot(211)
                    time_axis = np.arange(len(audio_data)) / sample_rate
                    plt.plot(time_axis, audio_data)
                    plt.title(f"音频波形 - {file_name}")
                    plt.xlabel("时间 (秒)")
                    plt.ylabel("振幅")
                    plt.grid(True)
                    
                    # 绘制包络线和阈值
                    plt.subplot(212)
                    plt.plot(time_axis, smooth_envelope, label="平滑包络线")
                    
                    # 标记不同阈值的截取点
                    colors = ['r', 'g', 'b', 'c', 'm', 'y']
                    for i, (threshold, (start, end)) in enumerate(cut_points.items()):
                        color = colors[i % len(colors)]
                        
                        # 绘制阈值线
                        plt.axhline(y=threshold, color=color, linestyle='--', 
                                    label=f"阈值 {threshold:.3f}")
                        
                        # 标记起始和结束点
                        plt.axvline(x=start/sample_rate, color=color, linestyle=':')
                        plt.axvline(x=end/sample_rate, color=color, linestyle=':')
                    
                    # 特别标记建议的阈值
                    plt.axhline(y=suggested_threshold, color='k', linestyle='-', 
                                label=f"建议阈值 {suggested_threshold:.3f}")
                    
                    plt.title("音频包络线和阈值分析")
                    plt.xlabel("时间 (秒)")
                    plt.ylabel("振幅")
                    plt.grid(True)
                    plt.legend()
                    
                    # 保存图表
                    plt.tight_layout()
                    plt.savefig(output_file)
                    plt.close()
                    
                    logger.info(f"已保存分析图表到: {output_file}")
                except Exception as e:
                    logger.error(f"生成分析图表失败: {str(e)}")
            
            # 返回分析结果
            result = {
                "file_name": os.path.basename(file_path),
                "sample_rate": sample_rate,
                "duration": len(audio_data) / sample_rate,
                "front_stats": {
                    "mean": float(front_mean),
                    "max": float(front_max),
                    "std": float(front_std)
                },
                "back_stats": {
                    "mean": float(back_mean),
                    "max": float(back_max),
                    "std": float(back_std)
                },
                "suggested_threshold": float(suggested_threshold),
                "cut_points": {str(k): v for k, v in cut_points.items()}
            }
            
            return result
        
        except Exception as e:
            logger.error(f"分析音频文件失败: {str(e)}")
            return None 